import 'dart:typed_data';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'package:image/image.dart' as img_lib;

// 实现思路参考 pixel_color_image库

class AlphaImageIgnorePointer extends StatelessWidget {
  /// size
  final Size size;

  /// assetPath
  final String? path;

  /// url
  final String? url;

  /// onTap
  final void Function()? onTap;

  /// imageBytes
  late final Uint8List imageBytes;

  AlphaImageIgnorePointer(
      {Key? key, required this.size, this.path, this.url, this.onTap})
      : super(key: key);

  /// from assets
  AlphaImageIgnorePointer.assetImage(
      {Key? key, required this.size, required this.path, this.onTap})
      : url = null,
        super(key: key);

  /// from network
  AlphaImageIgnorePointer.networkImage(
      {Key? key, required this.size, required this.url, this.onTap})
      : path = null,
        super(key: key);

  Future<Uint8List> _getImageBytesAsset(String path) async {
    WidgetsFlutterBinding.ensureInitialized();
    final byteData = await rootBundle.load(path);
    final uint8List = Uint8List.view(byteData.buffer);
    return uint8List;
  }

  Future<Uint8List> _getImageBytesUrl(String urlString) async {
    final url = Uri.parse(urlString);
    final http.Response response = await http.get(url);
    final uint8List = response.bodyBytes;
    return uint8List;
  }

  /// get image bytes
  Future<Uint8List> _getBytes() async {
    if (path != null) {
      return await _getImageBytesAsset(path!);
    }
    if (url != null) {
      return await _getImageBytesUrl(url!);
    }
    throw Exception('required assetPath | url');
  }

  Future<img_lib.Image?> _getImgLibImage() async {
    imageBytes = await _getBytes();
    final image = await _awaitDecodeImage(imageBytes);
    return image;
  }

  Future<img_lib.Image?> _awaitDecodeImage(
    Uint8List imageBytes,
  ) async {
    final result = await compute(_decodeImage, imageBytes);
    return result;
  }

  static img_lib.Image? _decodeImage(Uint8List imageBytes) {
    final decoder = _getDecoder(imageBytes);
    if (decoder == null) return null;
    return decoder.decodeImage(imageBytes);
  }

  static img_lib.Decoder? _getDecoder(
    Uint8List inputImg,
  ) {
    img_lib.PngDecoder pngDecoder = img_lib.PngDecoder();
    img_lib.JpegDecoder jpgDecoder = img_lib.JpegDecoder();
    if (pngDecoder.isValidFile(inputImg)) {
      return pngDecoder;
    } else if (jpgDecoder.isValidFile(inputImg)) {
      return jpgDecoder;
    } else {
      return null;
    }
  }

  Size _getImageSize(img_lib.Image image) {
    double width;
    double height;
    if (image.width > image.height) {
      width = size.width;
      height = image.height.toDouble() * size.width / image.width.toDouble();
    } else {
      height = size.height;
      width = image.width.toDouble() * size.height / image.height.toDouble();
    }
    return Size(width, height);
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
        height: size.height,
        width: size.width,
        child: FutureBuilder<img_lib.Image?>(
          future: _getImgLibImage(),
          builder: (context, snapshot) {
            img_lib.Image? result = snapshot.data;
            if (snapshot.connectionState == ConnectionState.done &&
                result != null) {
              final imageSize = _getImageSize(result);
              return Center(
                child: SizedBox(
                  width: imageSize.width,
                  height: imageSize.height,
                  child: AlphaIgnorePointer(
                    image: result,
                    containerSize: imageSize,
                    child: GestureDetector(
                      onTap: () {
                        onTap?.call();
                      },
                      child: Image.memory(imageBytes),
                    ),
                  ),
                ),
              );
            } else {
              return const SizedBox.shrink();
            }
          },
        ));
  }
}

class AlphaIgnorePointer extends SingleChildRenderObjectWidget {
  final img_lib.Image image;
  final Size containerSize;
  @override
  final Widget child;

  const AlphaIgnorePointer({
    Key? key,
    required this.image,
    required this.containerSize,
    required this.child,
  }) : super(key: key, child: child);

  @override
  AlphaRenderIgnorePointer createRenderObject(BuildContext context) {
    final displayedW = containerSize.width;
    final displayedH = containerSize.height;
    final pixelW = image.width;
    final pixelH = image.height;
    double hRatio = pixelH / displayedH;
    double wRatio = pixelW / displayedW;
    return AlphaRenderIgnorePointer(
      image: image,
      wRatio: wRatio,
      hRatio: hRatio,
    );
  }
}

class AlphaRenderIgnorePointer extends RenderProxyBox {
  final img_lib.Image image;
  final double wRatio;
  final double hRatio;

  AlphaRenderIgnorePointer({
    required this.image,
    required this.wRatio,
    required this.hRatio,
  });

  @override
  bool hitTest(BoxHitTestResult result, {required Offset position}) {
    return _hitUnIgnores(position) && super.hitTest(result, position: position);
  }

  bool _hitUnIgnores(Offset offset) {
    final pixelX = (offset.dx * wRatio).round();
    final pixelY = (offset.dy * hRatio).round();
    final pixel = image.getPixel(pixelX, pixelY);
    final truePixel = _abgrToArgb(pixel);
    final color = Color(truePixel);
    return color.alpha != 0;
  }

  int _abgrToArgb(int argbColor) {
    int r = (argbColor >> 16) & 0xFF;
    int b = argbColor & 0xFF;
    return (argbColor & 0xFF00FF00) | (b << 16) | r;
  }
}
